<template>
  <el-upload
    :class="dynamicClass"
    ref="upload"
    action
    :auto-upload="false"
    :accept="accept"
    :drag="drag"
    :multiple="multiple"
    :show-file-list="showFileList"
    :on-preview="handlePreview"
    :on-change="handelChange"
    :on-exceed="uploadExceed"
    :http-request="uploadFiles"
    :disabled="isDisabled || upLoading"
    :title="title"
    :limit="limit"
    v-loading="upLoading"
  >
    <slot />
  </el-upload>
</template>

<script>
import { notUploadFileType } from "@/util/uploadConfig";
import { Upload } from "@/util/upload";
import { Notify } from "@/util/notify";
import { Video } from "@/util/videoUrlFormat";
import { uploadmultifiles, verifyFile } from "@/request/upload";
import { UploadPart } from "@/util/uploadPart.js"
export default {
  data() {
    return {
      fileList: [],
      upLoading: false,
      allowedFileTypes: {
        '.html': "text/html", // html,
        '.js': "application/x-javascript", // js
        '.css': "text/css", // css
        '.txt': "text/plain", // txt
        '.excel': "application/vnd.ms-excel", // Microsoft Excel 表格
        '.xlx': "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", //xls
        '.xlsx': ".xlsx application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", // xlsx
        '.zip': "application/x-zip-compressed", // Zip files
        '.tar': "application/x-tar", // tar
        '.rar': "application/x-rar-compressed", // rar
        '.ppt' :"application/vnd.ms-powerpoint", // ppt
        '.pptx': "application/vnd.openxmlformats-officedocument.presentationml.presentation", // pptx
        '.pdf': "application/pdf", // PDF files
        '.doc': "application/msword", // Word files
        '.docx': "application/vnd.openxmlformats-officedocument.wordprocessingml.document", //docx
        '.csv': "text/csv", // CSV files
        '.png': "image/png", // PNG images
        '.jpeg': "image/jpeg", // JPG images
        '.gif': "image/gif", // gif
        '.mp3': "audio/x-mpeg", // mp3
        '.mp4': "video/mp4", // mp4
      }
    };
  },
  props: {
    accept: {
      type: String,
      default: () =>
        ".txt,.css,.html,.js,.zip,.rar,.jpg,.jpeg,.png,.gif,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx,.mp3,.mp4",
    },
    showFileList: Boolean,
    baseFileUrl: String,
    buttonType: {
      type: String,
      default: () => "text",
    },
    buttonSize: {
      type: String,
      default: () => "mini",
    },
    isStuShow: Boolean,
    isDisabled: Boolean,
    dynamicClass: {
      type: String,
      default: () => "custom-upload"
    },
    drag: Boolean,
    multiple: Boolean,
    title: {
      type: String,
      default: () => "上传文件"
    },
    isImportCourse: Boolean, // 是否导入课程
    taskJson: Object, // 学习任务数据
    uploadedFileList: Array, // 已上传的文件
    currNo: Number,
    isArchive: Boolean, // 是不是归档任务
    userInfo: Object, // 用户信息
    selectedTutorName: String, // 指导教师名字
    limit: {
      type: Number,
      default: () => ''
    }
  },
  computed: {
    getUploadedFileList() {
      return this.uploadedFileList
    }
  },
  methods: {
    handleRemove(file, fileList) {
    },
    handlePreview(file) {
    },
    // 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
    handelChange(file, fileList) {
      if (file.status == "ready") {
        if (this.timer) {
          clearTimeout(this.timer);
          this.timer = null;
        }
        this.timer = this.timeOutUpload();
      }
    },
    // 节流判断 upload组件 需要上传的文件 onchange是否已经结束
    timeOutUpload() {
      return setTimeout(() => {
        this.uploadFiles();
        clearTimeout(this.timer);
      }, 100);
    },
    uploadExceed() {
      this.$notify.warning({
          title:'提示',
          message: '您已添加了一个文件，如需替换，请先删除已添加的文件！',
      });
    },
    // 上传文件
    async uploadFiles() {
      this.upLoading = true
      let files = this.$refs.upload.uploadFiles;
      let uploadForm = new FormData();
      if (this.isImportCourse) return this.$emit("fileDataUploaded", files, files), this.upLoading = false; // emit第二个参数应该为空
      if(this.taskJson) uploadForm.append("taskJson", JSON.stringify(this.taskJson));
      const currNo = Number(this.currNo);
      const chunkSize = 2097152; // 5Mb
      const maxSize = 91457280;// 30Mb
      let hashArray = [];
      let fileRealNames = []
      let isDefaultUpload = false;
      const { type, message, time, dangerouslyUseHTMLString } = Upload.NotifyObj;
      let sendAPINotify = null // 如果需要发送上传文件请求，将notify对象赋值至此属性
      let allowedFileTypes = this.accept.split(',') || []
      
      if (this.limit && (this.getUploadedFileList?.length >= this.limit || files.length > this.limit)) {
        if (this.limit == 1) {
          this.$antdMessage.warning({
            content: '您已添加了一个文件，如需替换，请先删除已添加的文件！',
          });
        } else {
          this.$antdMessage.warning({
            content: '超出最大上传文件数！',
          });
        }
        // return之前需要清空上传组件里面的文件
        this.$refs.upload.clearFiles();
        this.upLoading = false
        return
      }
      for (let item of files) {
        // item.raw 文件源数据的文件名无法修改
        // const reg = new RegExp(/\s+/g); // 空格验证
        // if (reg.test(item.name)) {
        //   this.upLoading = false
        //   return this.$antdMessage.error({content: "文件名不能存在空格!"})
        // }
        console.log(allowedFileTypes, this.getFileExtension(item.raw.name), allowedFileTypes.includes(this.getFileExtension(item.raw.name)));
        
        if (!allowedFileTypes.includes(this.getFileExtension(item.raw.name))) {
          this.$antdMessage.warning({
            content: "文件格式错误",
          });
          if (files.length === 1) {
            this.upLoading = false
            this.$refs.upload.clearFiles();
            return
          }
          else continue // 阻止文件上传
        }
        let getAlikeFile = this.uploadedFileList?.find(uitem => uitem.fileName == item.name);
        let alikeFileData = null;
        if (getAlikeFile) {
          alikeFileData = await Upload.filterContentReturnHash(
            notUploadFileType,
            item,
            true,
            maxSize
          );
          if (!alikeFileData.hash) return this.upLoading = false;
        }
        let data = await Upload.filterContentReturnHash(
          notUploadFileType,
          item,
          true,
          maxSize
        );
        if (!data) {
          this.upLoading = false
          const uploadFiles = this.$refs.upload.uploadFiles;
          const index = uploadFiles.indexOf(item);
          uploadFiles.splice(index,1);
          return
        }
        let fileName = data.fileName.split(" ").join("");
        let hash = data.hash;
        if (getAlikeFile && alikeFileData.hash == hash) {
          this.upLoading = false;
          this.$refs.upload.clearFiles();
          // const uploadFiles = this.$refs.upload.uploadFiles;
          // const index = uploadFiles.indexOf(item);
          // uploadFiles.splice(index,1);
          this.$antdMessage.success({content: `${data.fileName}，此文已存在无需重复上传`})
          continue
        }
        if (!hash) {
          this.upLoading = false; // 文件hash失败则退出循环
          this.$refs.upload.clearFiles();
          return
        }
        let fileTag = null;
        if (this.isArchive) {
          // 任务名_引导文ID_学生学号_姓名_文件名
          fileTag = `${this.taskJson.taskName}_${this.taskJson.noInTask}_${this.selectedTutorName}_${this.userInfo.stuNum}_${this.userInfo.realName}`
          hash = fileTag
        } else {
          // 旧的上传fileTag是hash
          fileTag = hash
        }

        // 创建消息
        const notify = Notify.create(type, message, time, dangerouslyUseHTMLString);

        // 捕获verifyFile严重接口状态错误 跳出上传
        try {
          const vResult = await verifyFile({
            fileTag: fileTag,
            filename: fileName,
            currNo,
            baseFileUrl: this.baseFileUrl.substring(1),
            isStuShow: this.isStuShow,
            taskJson: this.taskJson,
          });

          if (vResult && vResult?.data?.shouldUpload) {
            //这里再进行文件上传操作，包括分片或者多文件上传
            if (item.size > chunkSize) {
              //如果文件大于规定大小，则进行分片上传
              const res = await UploadPart.tryUploadByChunks(item.raw, fileTag, currNo, this.isStuShow, vResult.data.uploadedList, this.baseFileUrl.substring(1), this.taskJson, chunkSize);
              if (res && res.data) {
                const fileUrl = res.data.filePaths
                if (fileUrl.length) this.formatData(res, fileUrl)
                Upload.uploadSuccessNotify(notify, 1500);
              } else {
                Upload.uploadErrorNotify(notify, "文件上传失败!", 1500);
              }

            }
            else {
              hashArray.push(hash)
              fileRealNames.push(fileName)
              //这里执行多文件上传的代码
              uploadForm.append("file", item.raw, fileName);
              isDefaultUpload = true
              // sendAPINotify = notify
              Upload.removeNotify(notify)
            }
          } else {
            //这里将返回的文件信息存到前端数组中！
            if (vResult.errno !== 0) {
              this.$antdMessage.error({ content: vResult.message })
              Upload.uploadErrorNotify(null, "文件验证失败!", 1500);
            } else {
              const noFormatObject = Object.assign({}, vResult.data.fileObj)
              const noAddPath = true
              // 格式化baseFileUrl,因为已经上传了的文件的baseFileUrl是/stutasks/xxx/xxx/xxx
              // 需要替换成 /files/stutasks/xxx/xxx/xxx
              const baseFileUrl = this.baseFileUrl.replace(/^\/?(?:files\/)?(stutasks(?:\/.*)?)$/,'/files/$1');
              const fomartData = Video.urlFormat(
                vResult.data.fileObj,
                baseFileUrl,
                noAddPath
              );
              // // 格式化文件数据格式
              this.fileList.push(fomartData);
              // 第三个参数控制：普通上传、归档上传文件后发送更新学习数据的请求，false为发送true为不发送请求
              this.$emit("fileDataUploaded", '',fomartData, noFormatObject, true);
              Upload.removeNotify(notify)
              Upload.uploadSuccessNotify(null, 1500);
              // Upload.uploadErrorNotify(notify, "文件已存在!", 1500);
            }
          }
        } catch (error) {
          Upload.uploadErrorNotify(notify, "文件验证失败!", 1500);
        }
      }

      if (this.isArchive) {
        uploadForm.append("isArchieve", true);
      }

      if (isDefaultUpload) {
        // 课程信息
        uploadForm.append("currNo", currNo);
        uploadForm.append("fileHashArray", JSON.stringify(hashArray))
        uploadForm.append("fileRealNames", JSON.stringify(fileRealNames))
        uploadForm.append("baseFileUrl", this.baseFileUrl.substring(1));
        await this.uploadFun(uploadForm, sendAPINotify)
      }
      // 调用父组件发送给taskType保存学习数据事件
      this.$parent.sendEmitToTaskTypeHandleSubmitData && this.$parent.sendEmitToTaskTypeHandleSubmitData()
      // 清除文件列表中的文件
      this.$refs.upload.clearFiles();
      this.upLoading = false
    },
    uploadFun(uploadForm, notify) {
      return new Promise((resolve, reject) => {
        // if (hashArray.length) {
        uploadmultifiles(uploadForm)
          .then((res) => {
            if (res.errno === 0) {
              Upload.uploadSuccessNotify(notify, 1500);
              let fileUrl = res.data.filePaths;
              if (fileUrl) {
                this.formatData(res, fileUrl)
              }
            } else {
              Upload.uploadErrorNotify(notify, "文件上传失败!", 1500);
            }
            resolve()
          })
          .catch((err) => {
            Upload.uploadErrorNotify(notify, err?.message || err)
            reject(notify, err?.message || err)
          });
        // }
      })
    },
    formatData(res, arr) {
      arr.forEach((item) => {
        let fileObj = {
          fileName: item.fileName || item.fileUrl,
          fileUrl: item.fileUrl,
          isDir: item.isDir,
          size: item.size || 0
        };
        const noFormatObject = Object.assign({}, fileObj)
        const noAddPath = true
        const fomartData = Video.urlFormat(
          fileObj,
          this.isStuShow ? false : res.data.baseFileUrl,
          noAddPath
        );
        // 格式化文件数据格式
        this.fileList.push(fomartData);
        // 第三个参数控制：普通上传、归档上传文件后发送更新学习数据的请求，false为发送true为不发送请求
        this.$emit("fileDataUploaded", res.data.baseFileUrl, fomartData, noFormatObject, true);
        this.$antdMessage.success({ content: "上传成功!" });
      });
    },
    // 获取文件后缀名
    getFileExtension(filename) {
        // 检查文件名中是否包含点号，且点号不在首位
        const lastDotIndex = filename.lastIndexOf('.');
        if (lastDotIndex === -1 || lastDotIndex === 0) {
            return ''; // 如果没有找到点号或者点号在首位，返回空字符串
        }

        // 获取点号后面的部分即为扩展名
        return filename.substring(lastDotIndex);
    }
    //  if (videoFiles.length) {
    //     let videoUploadForm = new FormData();
    //     for (let vi = 0; vi < videoFiles.length; vi++) {
    //       let fileName = videoFiles[vi].name; // 文件名
    //       fileName = Upload.filterEnSplit(fileName); // 过滤英文分号
    //       videoUploadForm.append("file", videoFiles[vi].raw, fileName); // 添加文件对象到formData
    //     }
    //     // 上传视频
    //     VideoUpload(videoUploadForm)
    //       .then((res) => {
    //         if (res && res.code == 200) {
    //           Upload.uploadSuccessNotify(notify, 1500);
    //           if (isType(res.data) === "Object") {
    //             this.uploadVideoPushData(
    //               res.data.hdAddress,
    //               res.data.baseFileUrl,
    //               true
    //             );
    //           }
    //           if (isType(res.data) === "Array") {
    //             res.data.forEach((item, index) => {
    //               // let nItem = Object.assign({}, item); 这里是否需要复制一个新的对象?
    //               const isLast = index + 1 === res.data.length;
    //               this.uploadVideoPushData(
    //                 item.hdAddress,
    //                 item.baseFileUrl,
    //                 isLast
    //               );
    //             });
    //           }
    //         } else {
    //           Upload.uploadErrorNotify(notify, 1500);
    //         }
    //       })
    //       .catch((err) => Upload.uploadErrorNotify(notify));
    //   }
    // // 上传完视频后
    // uploadVideoPushData(hdAddress, baseFileUrl, isEmit, isEncoded = false) {
    //   this.fileList.push(Video.urlFormat(this.formatVideoUrl(hdAddress)));
    //   this.saveUseFileList.push(this.formatVideoUrl(hdAddress));
    //   if (isEmit) {
    //     this.handleUploadDataChange(baseFileUrl, isEncoded);
    //   }
    // },
  },
};
</script>